package com.da.javatest.interview.session2;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import sun.misc.VM;

/**
 * @author chenlida
 * @date 2020/4/4 22:15
 * @description
 */
public class Test26OOM {
    public static void main(String[] args) {
        // stackOverflowError();
        // heapSpaceError(20);
        // overheadError();
        // directBufferError();
        // threadException();
        metaSpaceError();
    }

    /**
     * java.lang.StackOverflowError
     */
    private static void stackOverflowError() {
        stackOverflowError();
    }

    /**
     * java.lang.OutOfMemoryError: Java heap space
     *
     * -Xms10m -Xmx10m
     * 堆空间不够抛出该异常
     */
    private static void heapSpaceError(int i) {
        byte[] bytes = new byte[i * 1024 * 1024];
    }

    /**
     * java.lang.OutOfMemoryError: GC overhead limit exceeded
     *
     * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
     * GC时间远大于程序运行时间才抛出该异常
     */
    private static void overheadError() {
        int i = 0;
        List<String> list = new ArrayList<>();

        try {
            while (true) {
                list.add(String.valueOf(++i).intern());
            }
        } catch (Exception e) {
            System.out.println("**********************i=" + i);
            e.printStackTrace();
            throw e;
        }
    }

    /**
     * java.lang.OutOfMemoryError: Direct buffer memory
     *
     * ByteBuffer.allocate() 分配JVM堆内存，属于GC管控，由于需要拷贝(用户空间->内核空间)所以速度慢
     * ByteBuffer.allocateDirect() OS本地内存，不属于GC管控，由于无需内存拷贝所以速度相对要快
     * -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
     */
    private static void directBufferError() {
        System.out.println("系统直接内存大小为：" + VM.maxDirectMemory() / (double)1024 / 1024 + "MB");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ByteBuffer.allocateDirect(10 * 1024 * 1024);
    }

    /**
     * if (threadStatus != 0)
     * throw new IllegalThreadStateException();
     */
    private static void threadException() {
        Thread thread = new Thread();
        thread.start();
        thread.start();
    }

    /**
     * java.lang.OutOfMemoryError: unable to create new native thread
     *
     * 应用创建了太多线程，超过了系统的极限
     * linux默认允许单个进程最大创建1024个线程，超过了就会抛出这个错误
     */
    private static void newThreadError() {
        for (int i = 1; ; i++) {
            System.out.println("**************** i=" + i);
            new Thread(() -> {
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    /**
     * java.lang.OutOfMemoryError: Metaspace
     *
     * -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
     * 元空间 属于本地内存，存放了：虚拟机加载类的信息，常量池，静态变量，即时编译后的代码
     */
    private static void metaSpaceError() {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(MetaSpaceTest.class);
                enhancer.setUseCache(false);
                /**
                 * Object：由CGLib动态生成的代理类实例，
                 * Method：上文中实体类所调用的被代理的方法引用，
                 * Object[]：参数值列表，
                 * MethodProxy：生成的代理类对方法的代理引用。
                 */
                enhancer.setCallback(
                    (MethodInterceptor)(o, method, args, methodProxy) -> methodProxy.invokeSuper(o, args));
                enhancer.create();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("*****************i=" + i);
        }
    }

    static class MetaSpaceTest {}
}
